#include "gd32f30x.h"
#include "string.h"
#include "stdint.h"
#include "stdio.h"

#include "ff.h"

#include "DevicesCRC.h"
#include "taskSystem.h"

#include "DriverFile.h"


/* 磁盘句柄 */
FATFS g_fatFsDiskHandle;
/* 文件句柄 */
FIL g_fatFsFileHandle;


int8_t cFileScan(char *pcPath);


static int8_t cFileSyncLock(void)
{
//    xSemaphoreTakeRecursive(g_xFileSemaphore, portMAX_DELAY);

    return 0;
}

static int8_t cFileSyncUnlock(void)
{
//    xSemaphoreGiveRecursive(g_xFileSemaphore);

    return 0;
}

int8_t cFileInit(void)
{
    char cDirBuff[64] = "/";
    int8_t cError = 0;

    cFileSyncLock();

    /* 挂载磁盘 */
    if((cError = f_mount(&g_fatFsDiskHandle, "", 1)) == FR_NO_FILESYSTEM)
    {
        printf("磁盘没有文件系统.\r\n");

        return 1;

        /* 格式化磁盘 */
        f_mkfs("", NULL, g_fatFsDiskHandle.win, sizeof(g_fatFsDiskHandle.win));

        /* 挂载磁盘 */
        if((cError = f_mount(&g_fatFsDiskHandle, "", 1)) == FR_NO_FILESYSTEM)
        {
            printf("磁盘没有文件系统.\r\n");
        }
    }

    cFileSyncUnlock();

    /* 遍历目录 */
    cFileScan(cDirBuff);

    return cError;
}

/* 新建目录 */
int8_t cFileDirNew(char *pcPath)
{
    int8_t cError;

    cFileSyncLock();

    cError = f_mkdir(pcPath);

    cFileSyncUnlock();

    return cError;
}

/* 删除目录 */
int8_t cFileDirDel(char *pcPath)
{
    int8_t cError;

    cFileSyncLock();

    cError = f_unlink(pcPath);

    cFileSyncUnlock();

    return cError;
}

/* 更改目录名 */
int8_t cFileDirRename(char *pcPathOld, char *pcPathNew)
{
    int8_t cError;

    cFileSyncLock();

    cError = f_rename(pcPathOld, pcPathNew);

    cFileSyncUnlock();

    return cError;
}

/* 读取目录 */
int8_t cFileDirRead(char *pcPath, int32_t iOrder, void *pvDatas, int32_t iLength)
{
    FILINFO fno;
    DIR dir;
    int32_t i;
    int8_t cError = -1;

    memset(pvDatas, 0, iLength);

    cFileSyncLock();

    if(f_opendir(&dir, pcPath) == FR_OK)
    {
        for(i = 0; i < iOrder; ++i)
        {
            if((f_readdir(&dir, &fno) != FR_OK) || (fno.fname[0] == 0))
                break;
        }

        if(i == iOrder)
        {
            if((f_readdir(&dir, &fno) == FR_OK) && (fno.fname[0] != 0))
            {
                memcpy(pvDatas, dir.dir_pre, iLength);
                cError = 0;
            }
        }

        f_closedir(&dir);
    }

    cFileSyncUnlock();

    return cError;
}

/* 新建文件 */
int8_t cFileNew(char *pcPath)
{
    FIL fil;
    int8_t cError;

    cFileSyncLock();

    if((cError = f_open(&fil, pcPath, FA_WRITE | FA_CREATE_ALWAYS)) == FR_OK)
    {
        cError = f_close(&fil);
    }

    cFileSyncUnlock();

    return cError;
}

/* 删除文件 */
int8_t cFileDel(char *pcPath)
{
    return cFileDirDel(pcPath);
}

/* 重命名文件 */
int8_t cFileRename(char *pcPathOld, char *pcPathNew)
{
    return cFileDirRename(pcPathOld, pcPathNew);
}

/* 读取文件大小 */
int32_t iFileSizeGet(char *pcPath)
{
    FIL fil;
    int32_t iSize = 0;

    cFileSyncLock();

    if(f_open(&fil, pcPath, FA_READ) == FR_OK)
    {
        iSize = f_size(&fil);

        f_close(&fil);
    }

    cFileSyncUnlock();

    return iSize;
}

/* 写入文件 */
int8_t cFileWrite(char *pcPath, int32_t iOffset, void *pvDatas, int32_t iLength)
{
    FIL fil;
    int32_t iLengthTemp = 0;
    int8_t cError;

    cFileSyncLock();

    if((cError = f_open(&fil, pcPath, FA_WRITE | FA_OPEN_APPEND)) == FR_OK)
    {
        /* 偏移到指定位置 */
        cError = (iOffset >= 0) ? f_lseek(&fil, iOffset) : 0;

        cError |= f_write(&fil, pvDatas, iLength, (UINT *)&iLengthTemp);

        cError |= f_close(&fil);

        cError |= (iLengthTemp != iLength) ? FR_TOO_MANY_OPEN_FILES : 0;
    }

    cFileSyncUnlock();

    return cError;
}

/* 读取文件 */
int8_t cFileRead(char *pcPath, int32_t iOffset, void *pvDatas, int32_t iLength)
{
    FIL fil;
    int32_t iLengthRead = 0, iSize = 0;
    int8_t cError;

    cFileSyncLock();

    if((cError = f_open(&fil, pcPath, FA_READ)) == FR_OK)
    {
        /* 偏移到指定位置 */
        iSize = f_size(&fil);

        /* 偏移到指定位置 */
        cError = (iOffset >= 0) ? f_lseek(&fil, iOffset) : 0;

        iLength = iLength < (iSize - iOffset) ? iLength : (iSize - iOffset);

        cError |= f_read(&fil, pvDatas, iLength, (UINT *)&iLengthRead);

        cError |= f_close(&fil);

        cError |= (iLengthRead != iLength) ? FR_TOO_MANY_OPEN_FILES : 0;
    }

    cFileSyncUnlock();

    return cError;
}


/* 打开文件 */
int8_t cFileOpen(char *pcPath)
{
    int8_t cError;

    cFileSyncLock();

    cError = f_open(&g_fatFsFileHandle, pcPath, FA_WRITE | FA_OPEN_APPEND);

    cFileSyncUnlock();

    return cError;
}

/* 关闭文件 */
int8_t cFileClose(void)
{
    int8_t cError;

    cFileSyncLock();
    
    cError = f_close(&g_fatFsFileHandle);

    cFileSyncUnlock();

    return cError;
}

/* 设置文件偏移量 */
int8_t cFileOffsetSet(int32_t iOffset)
{
    int8_t cError;

    cFileSyncLock();

    cError = f_lseek(&g_fatFsFileHandle, iOffset);

    cFileSyncUnlock();

    return cError;
}

/* 写入文件 */
int8_t cFileWriteUnclose(int32_t iOffset, void *pvDatas, int32_t iLength)
{
    int32_t iLengthTemp = 0;
    int8_t cError;

    if(iLength <= 0)
        return 0;

    cFileSyncLock();

    /* 偏移到指定位置 */
    cError = (iOffset >= 0) ? f_lseek(&g_fatFsFileHandle, iOffset) : 0;

    cError |= f_write(&g_fatFsFileHandle, pvDatas, iLength, (UINT *)&iLengthTemp);

    cError |= (iLengthTemp != iLength) ? FR_TOO_MANY_OPEN_FILES : 0;

    cFileSyncUnlock();

    return cError;
}

uint32_t uiFileCrcGet(char *pcPath)
{
    uint32_t uiAddr = 0;
    int32_t iSize, iLength;
    uint16_t usCrc = 0xFFFF;
    uint8_t ucBuff[512];

    for(iSize = iFileSizeGet(pcPath); iSize > 0; iSize -= sizeof(ucBuff))
    {
        iLength = iSize > sizeof(ucBuff) ? sizeof(ucBuff) : iSize;

        cFileRead(pcPath, uiAddr, ucBuff, iLength);
        usCrc = usCRC16_MODBUS(&usCrc, ucBuff, iLength);

        uiAddr += sizeof(ucBuff);
    }

    return usCrc;
}


int8_t cFileScan(char *pcPath)
{
    static FILINFO fno;
    DIR dir;
    FRESULT res;
    int32_t i;

    if((res = f_opendir(&dir, pcPath)) == FR_OK)
    {
        while(1)
        {
            res = f_readdir(&dir, &fno);
            if (res != FR_OK || fno.fname[0] == 0)
                break;

            /* 目录 */
            if(fno.fattrib & AM_DIR)
            {
                i = strlen(pcPath);
                sprintf(&pcPath[i], "/%s", fno.fname);

                printf("Dir: %s\n", pcPath);

                if((res = cFileScan(pcPath)) != FR_OK)
                    break;

                pcPath[i] = 0;
            }
            /* 文件 */
            else
            {
                printf("File: %s/%s, size: %lld\n", pcPath, fno.fname, fno.fsize);
            }
        }

        f_closedir(&dir);
    }

    return res;
}
